package org.epanetgrid.otimizacao.replicador;

import java.util.ArrayList;
import java.util.List;

import org.epanetgrid.otimizacao.log.AGLogger;
import org.epanetgrid.otimizacao.util.OtimizacaoUtil;
import org.jheuristics.Individual;
import org.jheuristics.ga.DefaultPopulation;
import org.jheuristics.ga.Population;
import org.jheuristics.util.BitString;
import org.jheuristics.util.DefaultRandomGenerator;
import org.jheuristics.util.RandomGenerator;


/**
 * Classe com a implementa��o sugerida por Carlos Galv�o: Replica-se os 
 * indiv�duos que convergiram
 * @author vinicius
 *
 */
public class DefaultIndividualReplicator implements IIndividualReplicator{

	/* (non-Javadoc)
	 * @see org.smartpumping.otimizacao.replicador.IIndividualReplicator#replique(org.jheuristics.ga.Population)
	 */
	public Population replique(Population pop) {
		
		AGLogger logger = AGLogger.getInstance();
		
		
		StringBuffer buffer = new StringBuffer("\n=====================\nIniciando Replicação: \n");
		
		if(pop.size() == 0) {
			buffer.append("Não houve replicação: População com tamanho 0.\n");
			logger.info(buffer);
			return pop;
		}
		
		
		int tamanhoSaida = pop.size();
		
		Population popFinal = new DefaultPopulation();
		
		List<Individual> indConvergiram = new ArrayList<Individual>();
		
		for (Individual individual : pop.toIndividualArray()) {
			if(individual.getFitness() != null) {
				popFinal.addIndividual(individual);
				indConvergiram.add(individual);
			}
		}
		
		if(indConvergiram.size() == 0) {
			buffer.append("Não houve replicação: Nenhum indivíduo convergiu.\n");
			logger.info(buffer);
			return new DefaultPopulation();
		}
		
		if(popFinal.size() == tamanhoSaida) {
			buffer.append("Não houve replicação: Todos os indivíduos convergiram.\n");
			logger.info(buffer);
			return popFinal;
		}
		
		buffer.append("Número de indivíduos que não convergiram hidraulicamente: "+ (tamanhoSaida - popFinal.size()));
		buffer.append("\n");
		
		logger.info(buffer);
		
		buffer = new StringBuffer();
		
		buffer.append("Indivíduos que não convergiram: ");
		buffer.append("\n");
		
		for (Individual individual : pop.toIndividualArray()) {
			if(individual.getFitness() == null) {
				buffer.append(OtimizacaoUtil.gensToString((List<BitString>) individual.getGens()));
				buffer.append("\n");
			}
		}
		
		RandomGenerator randomGenerator = new DefaultRandomGenerator();
		
		buffer.append("Indivíduos serão replicados: ");
		buffer.append("\n");
		
		
		while(popFinal.size() != tamanhoSaida) {
			Individual replicado = indConvergiram.get(randomGenerator.nextInt(indConvergiram.size()));
			buffer.append(OtimizacaoUtil.gensToString((List<BitString>) replicado.getGens()));
			buffer.append("\n");
			popFinal.addIndividual(replicado);
		}
		
		logger.debug(buffer);
		
		return popFinal;
	}

}
